using System;
using System.Collections.Generic;

namespace FireStarter.CodeGeneration
{
    public class TemplateParser
    {
        private readonly ClassGenerator _generator;

        public TemplateParser(ClassGenerator generator)
        {
            _generator = generator;
        }

        public IDictionary<string, TagReplacement> ExtractAllTagReplacements(string templateContents)
        {
            IDictionary<string, TagReplacement> tagReplacements = new Dictionary<string, TagReplacement>(6);
            int pos = -1;
            TagReplacement tagReplacement = ExtractNextTagReplacement(templateContents, ref pos);
            while (tagReplacement != null)
            {
                tagReplacements.Add(tagReplacement.Tag, tagReplacement);
                tagReplacement = ExtractNextTagReplacement(templateContents, ref pos);
            }
            return tagReplacements;
        }

        public TagReplacement ExtractNextTagReplacement(string templateContents, ref int pos)
        {
            string tag = ExtractNextTag(templateContents, ref pos);
            if (string.IsNullOrEmpty(tag)) return null;
            string tagContent = ExtractTagContent(tag);
            if (IsForEachTag(tag))
            {
                return new TagReplacement(tag, GetForEachReplacement(tagContent));

            }
            return new TagReplacement(tag, GetValueReplacement(tagContent));
        }

        private static bool IsForEachTag(string tag)
        {
            return tag.Contains("FOREACH");
        }

        public static string ExtractTagContent(string tag)
        {
            const string startToken = "<<";
            const string endToken = ">>";
            return ExtractToken(tag, startToken, endToken);
        }

        private static string ExtractToken(string content, string startToken, string endToken)
        {
            if (content == null) throw new ArgumentNullException("content");
            if (startToken == null) throw new ArgumentNullException("startToken");
            if (endToken == null) throw new ArgumentNullException("endToken");
            int pos = content.IndexOf(startToken);
            if (pos >= 0)
            {
                int posEnd = content.IndexOf(endToken, pos);
                string tagContent = content.Substring(pos + startToken.Length, posEnd - pos - startToken.Length).Trim();
                return tagContent;
            }
            return "";
        }

        /// <summary>
        /// Extracts the collection name from the tag contents that has the syntax
        ///   FOREACH(collectionName) ....
        /// OR
        ///   FOREACH (collectionName) ....
        /// </summary>
        /// <param name="tagContent"></param>
        /// <returns></returns>
        public static string ExtractForEachCollectionName(string tagContent)
        {
            string collectionName = ExtractToken(tagContent, "FOREACH(", ")");
//            string collectionName = ExtractToken(tagContent, "FOREACH(", ")");
            return string.IsNullOrEmpty(collectionName) ? ExtractToken(tagContent, "FOREACH (", ")") : collectionName;
        }

        public static string ExtractForTemplateName(string tag)
        {
            throw new NotImplementedException();
        }

        private static ForEachReplacement GetForEachReplacement(string tagContent)
        {
            //TODO: Logic for creating a ForEachTemplateg
           //From the generator get the collection of all Model Elements
            // as per the collection defined in the tag contents
            // Create a tag template for each of the items in the collection
//            string collectionName = ExtractForEachCollectionName(tagContent);
//            IList<IModelClass> collection = _generator.GetModelElementsCollection(collectionName);
//            return new ForEachReplacement(collectionName, collection);
            ForEachReplacement forEachReplacement = new ForEachReplacement(tagContent, new ValueReplacement_old("Some value"));
            return forEachReplacement;
        }

        private ValueReplacement_old GetValueReplacement(string tagContent)
        {
            //string content = _generator.GetValueReplacementContent(tagContent);
            return new ValueReplacement_old(tagContent);
        }

        private static string ExtractNextTag(string templateContents, ref int pos)
        {
            pos = templateContents.IndexOf("<<", pos + 1);
            if (pos >= 0)
            {
                int posEnd = templateContents.IndexOf(">>", pos);
                CheckHasPosEnd(pos, posEnd);
                string tag = templateContents.Substring(pos, posEnd + 2 - pos).Trim();
                CheckValidTagName(tag);
                //TODO: Add template name and near text or location or something to error description

                pos = posEnd + 1;
                return tag;
            }
            return "";
        }

        private static void CheckValidTagName(string tag)
        {
            CheckTagNameNotEmpty(tag);

            if (tag.IndexOf("<<",1) != -1)
                throw new TemplateTagException
                    ("A tag is not formed correctly. ie. The '<<' of the tag has another '<<' before its corresponding '>>'");
        }

        private static void CheckTagNameNotEmpty(string tagName)
        {
            if (String.IsNullOrEmpty(tagName) || (tagName.Length <=4)) 
                    throw new TemplateTagException("A tag cannot be empty. ie. <<>> is invalid in the template");
        }

        private static void CheckHasPosEnd(int pos, int posEnd)
        {
            if (posEnd < pos +2)
                throw new TemplateTagException
                    ("A tag is not formed correctly. ie. The '<<' of the tag has no corresponding '>>'");
        }
    }
}